package main

//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
//to be modified as well with the new ID of chaincode_example02.
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
//hard-coding.

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	// "os"
	// "strings"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

// var myout *os.File

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

type Entity struct {
	Key   string `json:"key"`   //键
	Value string `json:"value"` //内容
	Time  string `json:"time"`  //上链时间
}

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	// myout, _ = os.Create("/opt/out")
	fmt.Println("Entity Init")
	// os.Stdout = myout
	// os.Stderr = myout

	fmt.Printf(" init success \n")
	return shim.Success(nil)
}

func (t *SimpleChaincode) CreateEntity(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	var Key string
	var Value string
	var Time string

	var entity Entity
	var err error

	if len(args) != 3 {
		return shim.Error("Incorrect number of arguments. Expecting 3")
	}

	// Initialize the chaincode
	Key = args[0]
	if err != nil {
		return shim.Error("Expecting integer value for asset holding：ID ")
	}
	Value = args[1]
	Time = args[2]

	entity.Key = Key
	entity.Value = Value
	entity.Time = Time

	jsons, errs := json.Marshal(entity) //转换成JSON返回的是byte[]
	if errs != nil {
		return shim.Error(errs.Error())
	}

	// Write the state to the ledger
	// k := []string{"Key", args[0]}
	// kk, _ := stub.CreateCompositeKey("XXX", k)

	err = stub.PutState("Key"+Key, jsons)
	if err != nil {
		fmt.Println(err)
		fmt.Printf("put state err : key = %s, value =%s, time%s\n", Key, Value, Time)
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

//getEntity
func (t *SimpleChaincode) GetEntity(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	fmt.Println("getEneity")

	var Key string // ID
	var entity_Info Entity
	var err error

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	Key = args[0]

	// Key, _ = stub.CreateCompositeKey("XXX", []string{"Key", Key})
	entityInfo, erro := stub.GetState("Key" + Key)
	if erro != nil {
		fmt.Println("get key error ", err)
		fmt.Println(Key)
		return shim.Error(erro.Error())
	}
	if len(entityInfo) == 0 {
		return shim.Error("Key Not Found")
	}
	//将byte的结果转换成struct
	err = json.Unmarshal(entityInfo, &entity_Info)
	if err != nil {
		fmt.Println("get key error 2 ", err)
		fmt.Println(Key)

		return shim.Error(err.Error())
	}
	fmt.Printf("entity_Info  = %d  \n", entity_Info)
	fmt.Printf("getEntity successed \n")

	return shim.Success(entityInfo)
}

//getEntityByRange
func (t *SimpleChaincode) GetEntityByRange(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	var startKey string
	var endKey string

	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting abc 2")
	}

	startKey = args[0]
	endKey = args[1]

	resultsIterator, erro := stub.GetStateByRange("Key"+startKey, "Key"+endKey)
	if erro != nil {
		fmt.Println("get range key error ", startKey, "", endKey)
		fmt.Println(erro)
		return shim.Error(erro.Error())
	}

	defer resultsIterator.Close()

	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			fmt.Println("get range key error  2", startKey, "", endKey)
			fmt.Println(err)
			return shim.Error(err.Error())
		}
		// 在数组成员前加一个逗号
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}
		buffer.WriteString("{\"Key\":")
		buffer.WriteString("\"")
		buffer.WriteString(queryResponse.Key)
		buffer.WriteString("\"")

		buffer.WriteString(", \"Value\":")
		// Record 是一个JSON对象，所以我们按原样写
		buffer.WriteString(string(queryResponse.Value))
		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")

	return shim.Success(buffer.Bytes())
}

func (t *SimpleChaincode) GetEntityByPartialCompositeKey(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	log.Println("in")
	log.Println(len(args))
	// if len(args) < 2 {
	// 	return shim.Error("xxxx================= cting 2")
	// }
	keys := args[1:]

	objectType := args[0]
	if len(args) == 1 {
		keys = []string{}
	}

	// return shim.Error(strings.Join(args, "\t"))

	shim.SetLoggingLevel(shim.LogDebug)
	log.Println("getValue ", args)
	log.Println("xxxxxxxxx=====================")
	log.Println("xxxxxxxxx=====================")
	log.Println("xxxxxxxxx=====================")
	log.Println("xxxxxxxxx=====================")
	log.Println(keys, len(keys))
	log.Println("xxxxxxxxx=====================")
	log.Println("xxxxxxxxx=====================")
	log.Println("xxxxxxxxx=====================")
	log.Println("xxxxxxxxx=====================")
	log.Println("xxxxxxxxx=====================")
	log.Println("xxxxxxxxx=====================")

	shim.SetLoggingLevel(shim.LogError)

	// stub.GetStateByPartialCompositeKey(objectType, keys)
	// stub.GetStateByPartialCompositeKey(objectType, keys)
	resultsIterator, erro := stub.GetStateByPartialCompositeKey(objectType, keys)
	if erro != nil {
		fmt.Println("get range key error ", objectType, keys)
		fmt.Println(erro)
		return shim.Error(erro.Error())
	}

	fmt.Println(resultsIterator.HasNext())

	defer resultsIterator.Close()

	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		fmt.Println("xxxx\n")
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			fmt.Println("get range key error ", objectType, keys)
			fmt.Println(err)
			return shim.Error(err.Error())
		}
		// 在数组成员前加一个逗号
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}
		buffer.WriteString("{\"Key\":")
		buffer.WriteString("\"")
		buffer.WriteString(queryResponse.Key)
		buffer.WriteString("\"")

		buffer.WriteString(", \"Value\":")
		// Record 是一个JSON对象，所以我们按原样写
		buffer.WriteString(string(queryResponse.Value))
		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]abc")

	return shim.Success(buffer.Bytes())
}

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println("entity Invoke")

	function, args := stub.GetFunctionAndParameters()
	switch function {
	case "invoke":
		return t.invoke(stub, args)
	case "query":
		return t.query(stub, args)
	case "CreateEntity":
		return t.CreateEntity(stub, args)
	case "GetEntity":
		return t.GetEntity(stub, args)
	case "GetEntityByRange":
		return t.GetEntityByRange(stub, args)

	case "GetEntityByPartialCompositeKey":
		return t.GetEntityByPartialCompositeKey(stub, args)
	}

	return shim.Error("Invalid invoke function name a b c ")
}

// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	return shim.Success(nil)
}

// Deletes an entity from state

// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var A string // Entities
	//var err error

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
	}

	A = args[0]

	// Get the state from the ledger
	Avalbytes, erro := stub.GetState(A)
	if erro != nil {
		return shim.Error(erro.Error())
	}
	//fmt.Printf("Query Response:%s\n", jsonResp)
	return shim.Success(Avalbytes)
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
